#pragma once

#include<iostream>
#include<pthread.h>
#include<functional>
#include<queue>
#include<vector>
#include<unistd.h>
#include<string>

#include"Log.hpp"

//线程封装
class Pthread
{
public:
    Pthread(std::function<void()> func,std::string name)
        :_func(func)
        ,_pthread_name(name)
    {}

    ~Pthread()
    {}

    static void* thread_func(void* arg)
    {
        Pthread* p=reinterpret_cast<Pthread*>(arg);
        p->_func();
        return nullptr;
    }

    void Start()
    {
        if(-1==pthread_create(&_pthread_id,NULL,thread_func,this))
        {
            Log(ERROR,"pthread_create");
            return;
        }
    }

    void Wait()
    {
        pthread_join(_pthread_id,NULL);
    }

    void Detach()
    {
        pthread_detach(_pthread_id);
    }

    std::string GetPthreadName()
    {
        return _pthread_name;
    }
  
private:
    pthread_t _pthread_id;//线程ID
    std::string _pthread_name;//线程名
    std::function<void()> _func;//线程执行的函数
};

template<class T>
class ThreadPool
{
public:
    ThreadPool(size_t threads_num=3)
        :_threads_num(threads_num)
        ,_wait_num(0)
    {
        Log(DEBUG,"threads pool init\n");
        _tp.reserve(threads_num);
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_cond,nullptr);
    }

    ~ThreadPool()
    {
        Log(DEBUG,"thread pool destroy\n");
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

    void Thread_func()
    {
        Log(DEBUG,"thread execute\n");
        while(true)
        {
            pthread_mutex_lock(&_mutex);
            while(_task.empty())
            {
                ++_wait_num;
                pthread_cond_wait(&_cond,&_mutex);
                --_wait_num;
            }
            Log(DEBUG,"thread get task\n");
            T t=_task.front();
            _task.pop();
            pthread_mutex_unlock(&_mutex);
            Log(DEBUG,"thread starts to execute task\n");
            t();
            Log(DEBUG,"thread completed task\n");
        }
    }

    void Start()
    {
        Log(DEBUG,"threads Start\n");
        int i=0;
        for(i=0;i<_threads_num;++i)
        {
            _tp.emplace_back(Pthread(bind(&ThreadPool::Thread_func,this),"Thread"+to_string(i)));
            _tp.back().Start();
        }
    }

    void PushTask(T t)
    {
        Log(DEBUG,"PushTask\n");
        pthread_mutex_lock(&_mutex);
        _task.push(t);
        pthread_cond_signal(&_cond);
        pthread_mutex_unlock(&_mutex);
    }

    void Wait()
    {                            
        Log(DEBUG,"threads wait\n");
        for(auto& e:_tp)
        {
            e.Wait();
        }
        Log(DEBUG,"threads end wait\n");
    }

private:
    queue<T> _task;//任务队列
    vector<Pthread> _tp;//线程池
    pthread_mutex_t _mutex;//用于对任务队列加锁保护
    pthread_cond_t _cond;//线程在该条件变量下面等待任务分配
    size_t _threads_num;//线程池中线程个数
    size_t _wait_num;//休眠中的线程个数
};